/**
 * Copyright 2009-2011 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.myjung.generator;

import java.io.BufferedReader;
import java.io.StringReader;
import java.util.List;
import java.util.Properties;
import java.util.SortedSet;
import java.util.TreeSet;

import net.myjung.Myjung;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.StringUtils;

/**
 * @author Steve M. Jung
 */
public abstract class AbstractGenerateJavaServlet extends AbstractGenerateZipServlet {
	private static final long serialVersionUID = 1L;
	private static Log logger = LogFactory.getLog(AbstractGenerateJavaServlet.class);

	protected static final String OPTION_JAVAPATH = "javaPath";
	protected static final String OPTION_WEBAPPPATH = "webappPath";
	protected static final String OPTION_CONTEXTCONFIGPATH = "contextConfigPath";
	protected static final String OPTION_CONTEXTCONFIGPREFIX = "contextConfigPrefix";

	protected static String toPackagePath(String path, String javaPath, String pkgName) {
		if (Myjung.isEmpty(javaPath)) {
			javaPath = "/src";
		} else {
			if (!javaPath.startsWith("/"))
				javaPath = new StringBuffer("/").append(javaPath).toString();
			if (javaPath.endsWith("/"))
				javaPath = javaPath.substring(0, javaPath.lastIndexOf("/"));
		}
		StringBuffer pkgPathBuf = new StringBuffer(path).append(javaPath);
		if (Myjung.isEmpty(pkgName))
			return pkgPathBuf.toString();
		String[] pkgPaths = StringUtils.tokenizeToStringArray(pkgName, ".");
		for (String pkgPath : pkgPaths)
			pkgPathBuf.append("/").append(pkgPath);
		return pkgPathBuf.toString();
	}
	protected static String toPackageName(String className) {
		className = toValidName(className);
		if (className.indexOf(".") < 1)
			return "";
		return className.substring(0, className.lastIndexOf("."));
	}
	protected static String toSimpleName(String className) {
		className = toValidName(className);
		if (className.indexOf(".") < 1)
			return className;
		return className.substring(className.lastIndexOf(".") + 1);
	}
	protected static String toSimpleName(String prefix, String className) {
		className = toSimpleName(className);
		if (Myjung.isEmpty(prefix))
			return className;
		if (className.equals("Factory"))
			className = "_Factory";
		else if (className.equals("Exception"))
			className = "_Exception";
		return new StringBuffer(prefix).append(className).toString();
	}
	protected static String toSource(String source, String tab) {
		return toSource(source, tab, "");
	}
	protected static String toSource(String source, String tab, String ann) {
		if (Myjung.isEmpty(source))
			return "";
		StringBuffer buf = new StringBuffer();
		StringReader reader = null;
		BufferedReader br = null;
		try {
			reader = new StringReader(source);
			br = new BufferedReader(reader);
			String str;
			int line = 0;
			String _tab = "";
			while ((str = br.readLine()) != null) {
				if (line == 1 && !str.startsWith(tab))
					_tab = tab;
				if (line++ > 0)
					buf.append("\r\n");
				else if (!str.startsWith(tab))
					buf.append(tab);
				buf.append(ann).append(_tab).append(str);
			}
		} catch (Exception e) {
			logger.warn(e, e);
		} finally {
			Myjung.close(br);
			Myjung.close(reader);
		}
		return buf.toString();
	}
	protected static String toClassSource(String pkgName, List<String> imports, StringBuffer classBuf, StringBuffer fieldsBuf, StringBuffer methodsBuf) {
		SortedSet<String> importSet = new TreeSet<String>(imports);

		// Package
		StringBuffer buf = new StringBuffer();
		if (!Myjung.isEmpty(pkgName))
			buf.append("package ").append(pkgName).append(";");

		buf.append("\r\n");

		// Imports
		if (!Myjung.isEmpty(importSet)) {
			String prevPrefix = null;
			boolean imported = false;
			for (String importClassName : importSet) {
				String importPkgName = toPackageName(importClassName);
				if (Myjung.isEqual(pkgName, importPkgName))
					continue;
				if (prevPrefix == null || !importClassName.startsWith(prevPrefix)) {
					if (prevPrefix != null)
						buf.append("\r\n");
					prevPrefix = Myjung.isEmpty(importPkgName) ? "" : importPkgName + ".";
				}
				buf.append("\r\nimport ").append(importClassName).append(";");
				imported = true;
			}
			if (imported)
				buf.append("\r\n");
		}

		buf.append("\r\n");

		// Class
		buf.append(classBuf);

		buf.append(" {");
		buf.append("\r\n");

		// Fields
		if (!Myjung.isEmpty(fieldsBuf)) {
			buf.append(fieldsBuf);
			buf.append("\r\n");
		}

		// Getter/Setters
		if (!Myjung.isEmpty(methodsBuf))
			buf.append(methodsBuf);

		buf.append("\r\n");
		buf.append("}");

		return buf.toString();
	}
	protected static String toFieldName(String name) {
		if (name == null)
			return null;
		if (name.equals("class"))
			return "clazz";
		else if (name.equals("extends"))
			return "extendz";
		else if (name.equals("package"))
			return "pkg";
		else if (name.equals("import"))
			return "_import";
		else if (name.equals("default"))
			return "_default";
		return toValidName(name);
	}
	protected static String toGetterSetterName(String name) {
		if (name.equals("Class"))
			return "Clazz";
		else if (name.equals("class"))
			return "clazz";
		return toValidName(name);
	}
	protected static String toGetterSetterUpperName(String name) {
		name = toGetterSetterName(name);
		return (name.length() > 1 && Character.isUpperCase(name.charAt(1))) ? name : Myjung.toUpperCase(name, 0);
	}
	protected static String toValidName(String name) {
		name = StringUtils.replace(name, "-", "_").trim();
		name = StringUtils.replace(name, ":", "_");
		return name;
	}
	protected static String toPath(String path) {
		if (Myjung.isEmpty(path))
			return "/";
		if (path.indexOf(":") == -1 && !path.startsWith("/"))
			path = new StringBuffer("/").append(path).toString();
		if (path.endsWith("/"))
			path = path.substring(0, path.lastIndexOf("/"));
		return path;
	}
	protected static String toId(String prefix, String name) {
		if (!Myjung.isEmpty(prefix)
				&& (name.equalsIgnoreCase("factory") || name.equalsIgnoreCase("manager") || name.equalsIgnoreCase("managertarget") || name
						.equalsIgnoreCase("managerinterceptor")))
			name = "_" + name;
		return Myjung.isEmpty(prefix) ? name : new StringBuffer(prefix).append(Myjung.toUpperCase(name, 0)).toString();
	}
	protected static StringBuffer openWebBuf(String name, String web, Properties props) {
		StringBuffer buf = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
		// webBuf.append("\r\n<!DOCTYPE web-app PUBLIC \"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN\" \"http://java.sun.com/dtd/web-app_2_3.dtd\">");
		buf.append("\r\n<web-app ");
		buf.append("\r\n\txmlns=\"http://java.sun.com/xml/ns/javaee\" ");
		buf.append("\r\n\txmlns:web=\"http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd\" ");
		buf.append("\r\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" ");
		buf.append("\r\n\txsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd\" ");
		buf.append("\r\n\tversion=\"2.5\">");

		buf.append(Myjung.isEmpty(web) || web.indexOf("<display-name>") == -1 ? new StringBuffer("\r\n\t<display-name>")
				.append(Myjung.escapeXml(name)).append("</display-name>\r\n").toString() : "");

		String rnId = "<rep:rn>";
		web = StringUtils.replace(web, "\r\n", rnId);
		web = StringUtils.replace(web, "\r", rnId);
		web = StringUtils.replace(web, "\n", rnId);
		web = StringUtils.replace(web, rnId, "\r\n");

		if (!Myjung.isEmpty(web))
			buf.append("\r\n\t").append(web).append("\r\n");

		buf.append("\r\n\t<listener>");
		buf.append("\r\n\t\t<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>");
		buf.append("\r\n\t</listener>");
		buf.append("\r\n\t<context-param>");
		buf.append("\r\n\t\t<param-name>contextConfigLocation</param-name>");
		buf.append("\r\n\t\t<param-value>");
		buf.append(props == null || !props.containsKey("contextConfigLocation") ? "/WEB-INF/beans*.xml" : props.getProperty("contextConfigLocation"));
		buf.append("</param-value>");
		buf.append("\r\n\t</context-param>");

		return buf;
	}
	protected static void closeWebBuf(StringBuffer buf) {
		buf.append("\r\n</web-app>");
	}
	protected static void appendOpenSessionInViewFilterDef(StringBuffer buf, String prefix) {
		String openSessionInViewFilterId = toId(prefix, "openSessionInViewFilter");
		buf.append("\r\n\t<filter>");
		buf.append("\r\n\t\t<filter-name>").append(openSessionInViewFilterId).append("</filter-name>");
		buf.append("\r\n\t\t<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>");
		buf.append("\r\n\t\t<init-param>");
		buf.append("\r\n\t\t\t<param-name>sessionFactoryBeanName</param-name>");
		buf.append("\r\n\t\t\t<param-value>").append(toId(prefix, "sessionFactory")).append("</param-value>");
		buf.append("\r\n\t\t</init-param>");
		buf.append("\r\n\t</filter>");
		buf.append("\r\n\t<filter-mapping>");
		buf.append("\r\n\t\t<filter-name>").append(openSessionInViewFilterId).append("</filter-name>");
		buf.append("\r\n\t\t<url-pattern>/*</url-pattern>");
		buf.append("\r\n\t\t<dispatcher>REQUEST</dispatcher>");
		buf.append("\r\n\t\t<dispatcher>FORWARD</dispatcher>");
		buf.append("\r\n\t</filter-mapping>");
	}
}